package ru.ipo.dces.plugins.admin;

import info.clearthought.layout.TableLayout;
import ru.ipo.dces.client.Controller;
import ru.ipo.dces.client.Localization;
import ru.ipo.dces.client.components.ContestChoosingPanel;
import ru.ipo.dces.clientservercommunication.AcceptedResponse;
import ru.ipo.dces.clientservercommunication.ContestDescription;
import ru.ipo.dces.clientservercommunication.UserDescription;
import ru.ipo.dces.pluginapi.Plugin;
import ru.ipo.dces.pluginapi.PluginEnvironment;
import ru.ipo.dces.plugins.admin.components.ContestRegistrationPanel;
import ru.ipo.dces.plugins.admin.components.ContestUsersTable;
import ru.ipo.dces.plugins.admin.components.JTableSearcher;
import ru.ipo.dces.plugins.admin.packetregistration.Csv;
import ru.ipo.dces.plugins.admin.packetregistration.passwordgenerator.PasswordGenerator3D;
import ru.ipo.dces.server.ServerFailReason;
import ru.ipo.dces.utils.ResponseHandler;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.*;
import java.util.List;

public class ManageUsersPluginV2 extends JPanel implements Plugin {

    private static final int separatorGap = 5;
    private static final int verticalGap = 10;
    private ContestChoosingPanel contestChoosingPanel;
    private final ContestUsersTable contestUsersTable = new ContestUsersTable();
    private ContestRegistrationPanel.RegistrationPanel registrationPanel = new ContestRegistrationPanel.RegistrationPanel();
    private JTableSearcher searcher = new JTableSearcher(contestUsersTable);

    public ManageUsersPluginV2(PluginEnvironment env) {
        env.setTitle(Localization.getAdminPluginName(ManageUsersPluginV2.class));

        contestUsersTable.putClientProperty("JTable.autoStartsEdit", Boolean.TRUE);
        contestUsersTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
        setupUI();
    }

    public JPanel getPanel() {
        return this;
    }

    public void activate() {
        if (Controller.isContestUnknownMode())
            contestChoosingPanel.refreshContestList();
    }

    public void deactivate() {
        //do nothing
    }

    private void setupUI() {

        setLayout(new TableLayout(
                new double[]{separatorGap, 275, separatorGap, TableLayout.PREFERRED, TableLayout.FILL, 275, separatorGap},
                new double[]{verticalGap, TableLayout.PREFERRED, separatorGap, TableLayout.FILL, separatorGap,
                        TableLayout.PREFERRED, TableLayout.PREFERRED, verticalGap}
        ));
        final BottomMiddlePanel bottomMiddlePanel = new BottomMiddlePanel();
        if (Controller.isContestUnknownMode()) {
            contestChoosingPanel = new ContestChoosingPanel();
            contestChoosingPanel.setPopup(true);
            contestChoosingPanel.addContestChangedActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    ContestDescription contest = contestChoosingPanel.getContest();

                    if (contest == null) {
                        registrationPanel.resetPanel();
                        return;
                    }

                    registrationPanel.setContest(contest);
                    contestUsersTable.setContest(contest);
                    bottomMiddlePanel.setContest(contest);
                }
            });
            add(contestChoosingPanel, "1, 1, 5, 1");
        }
        add(new JScrollPane(contestUsersTable), "1, 3, 5, 3");
        add(searcher, "5, 5");

        registrationPanel.setPreferredSize(new Dimension(275, 200));
        add(registrationPanel, "1, 5, 1, 6");
        registrationPanel.addRegistrationListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                contestUsersTable.refreshContest();
            }
        });
        add(bottomMiddlePanel, "3, 5, 3, 6");

        if (!Controller.isContestUnknownMode()) {
            ContestDescription contest = Controller.getContestConnection().getContest();
            contestUsersTable.setContest(contest);
            registrationPanel.setContest(contest);
            bottomMiddlePanel.setContest(contest);
        }
    }

    private class BottomMiddlePanel extends JPanel {

        private JButton delete = new JButton("Удалить");
        private JButton registrationFromFile = new JButton("Пакетная регистрация");
        private ContestDescription contest;

        public BottomMiddlePanel() {
            setLayout(new TableLayout(
                    new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED},
                    new double[]{separatorGap, TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED, separatorGap}
            ));
            add(delete, "0, 1");
            add(registrationFromFile, "0, 3, 1, 3");

            delete.setEnabled(false);
            registrationFromFile.setEnabled(false);
            addListeners();
        }

        public void setContest(ContestDescription contest) {
            delete.setEnabled(!(contest == null));
            registrationFromFile.setEnabled(!(contest == null));
            this.contest = contest;
        }

        private void addListeners() {
            delete.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent actionEvent) {
                    if (contestUsersTable.getSelectedColumn() == -1) {
                        JOptionPane.showMessageDialog(
                                ManageUsersPluginV2.this,
                                "Выберете записи для удаления");
                        return;
                    }
                    if (JOptionPane.showConfirmDialog(
                            ManageUsersPluginV2.this,
                            "Вы действительно хотите удалить выбранных участников?",
                            "Удаление",
                            JOptionPane.YES_NO_OPTION
                    ) == JOptionPane.NO_OPTION) return;

                    int[] vIndexes = contestUsersTable.getSelectedRows();
                    int[] mIndexes = new int[vIndexes.length];
                    for (int i = 0; i < vIndexes.length; i++)
                        mIndexes[i] = contestUsersTable.convertRowIndexToModel(vIndexes[i]);

                    ResponseHandler<AcceptedResponse> handler = new ResponseHandler<AcceptedResponse>() {
                        @Override
                        public void success(AcceptedResponse response) {
                            ((AbstractTableModel) contestUsersTable.getModel()).fireTableStructureChanged();
                        }

                        @Override
                        public void fail(ServerFailReason exception) {
                        }
                    };
                    for (int index : mIndexes) {
                        int userID = (Integer) contestUsersTable.getModel().getValueAt(index, 0);
                        Controller.removeUser(userID, handler);
                    }
                }
            });

            registrationFromFile.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent actionEvent) {
                    if (contest == null) {
                        //should not occur because this button is disabled when contest == null
                        JOptionPane.showMessageDialog(ManageUsersPluginV2.this, "Необходимо выбрать соревнование");
                        return;
                    }

                    JFileChooser chooser = new JFileChooser();
                    FileNameExtensionFilter filter = new FileNameExtensionFilter("Csv files", "csv");
                    chooser.setFileFilter(filter);
                    int returnVal = chooser.showOpenDialog(ManageUsersPluginV2.this);
                    File csvFile;
                    if (returnVal == JFileChooser.APPROVE_OPTION)
                        csvFile = chooser.getSelectedFile();
                    else
                        return;

                    String directoryName = csvFile.getAbsolutePath().
                            substring(0, csvFile.getAbsolutePath().lastIndexOf("/") + 1);
                    String csvNameWithFilenameExtension = csvFile.getAbsolutePath().
                            substring(csvFile.getAbsolutePath().lastIndexOf("/") + 1);
                    String csvName = csvNameWithFilenameExtension.
                            substring(0, csvNameWithFilenameExtension.lastIndexOf(".csv"));

                    Csv.Reader reader;
                    try {
                        reader = new Csv.Reader(new FileReader(csvFile)).delimiter(',').ignoreComments(true);
                    } catch (FileNotFoundException e) {
                        JOptionPane.showMessageDialog(ManageUsersPluginV2.this, "Файл не найден", "Ошибка",
                                JOptionPane.ERROR_MESSAGE);
                        return;
                    }
                    List<String> result;
                    List<List<String>> resultDataSet = new ArrayList<List<String>>();
                    while (true) {
                        result = reader.readLine();
                        if (result == null)
                            break;
                        if (!checkCsvLineFormat(result)) {
                            JOptionPane.showMessageDialog(ManageUsersPluginV2.this, "Неверный формат файла", "Ошибка",
                                    JOptionPane.ERROR_MESSAGE);
                            return;
                        }
                        resultDataSet.add(result);
                    }

                    File passFile = new File(directoryName + csvName + "_pass.csv");
                    for (int i = 1; passFile.exists(); i++)
                        passFile = new File(directoryName + csvName + "_pass(" + i + ").csv");

                    File logFile = new File(directoryName + csvName + "_log.csv");
                    for (int i = 1; logFile.exists(); i++)
                        logFile = new File(directoryName + csvName + "_log(" + i + ").csv");

                    final Csv.Writer logWriter = new Csv.Writer(logFile.getAbsoluteFile()).delimiter(',');
                    final Csv.Writer passWriter = new Csv.Writer(passFile.getAbsolutePath()).delimiter(',');
                    for (final List<String> data : resultDataSet) {
                        final String[] dataValue = new String[data.size() - 2];
                        if (dataValue.length > 0)
                            for (int i = 0; i < dataValue.length; i++)
                                dataValue[i] = data.get(i + 2);

                        final char[] password;
                        if (data.get(1).equals("*"))
                            password = new PasswordGenerator3D().getWord(10).toCharArray();
                        else
                            password = data.get(1).toCharArray();

                        ResponseHandler<AcceptedResponse> handler = new ResponseHandler<AcceptedResponse>() {
                            @Override
                            public void success(AcceptedResponse response) {
                                passWriter.value(data.get(0)).value(new String(password));
                                for (String field : dataValue)
                                    passWriter.value(field);
                                passWriter.newLine();

                                for (String field : data)
                                    logWriter.value(field);
                                logWriter.value("success").newLine();
                                ((AbstractTableModel) contestUsersTable.getModel()).fireTableStructureChanged();  // update records
                            }

                            @Override
                            public void fail(ServerFailReason exception) {
                            }
                        };
                        Controller.addUser(data.get(0), password, dataValue,
                                UserDescription.UserType.Participant, contest.contestID, handler);


                    }
                    ((AbstractTableModel) contestUsersTable.getModel()).fireTableStructureChanged();  // update records
                    logWriter.close();
                    passWriter.close();
                }
            });
        }

        private boolean checkCsvLineFormat(List<String> list) {
            int contestUserFieldsLength;
            //TODO move the check to the controller. Let it remove all null UserDataFields
            if (contest.data.length == 1 && contest.data[0] == null)
                contestUserFieldsLength = 0;
            else
                contestUserFieldsLength = contest.data.length;

            return contestUserFieldsLength == (list.size() - 2); // login + password + fields
        }
    }
}